open Ast
open Bytecode
open Thread

exception IllegalPrint;;
exception IllegalMove;;

let trim s =
  let s' = Str.replace_first (Str.regexp "^[ \t\n]+") "" s in
  Str.replace_first (Str.regexp "[ \t\n]+$") "" s';;
  
let explode s =
  let rec f acc = function
    | -1 -> acc
    | k -> f (s.[k] :: acc) (k - 1)
  in f [] (String.length s - 1) ;;

(*execute the program*)
let execute_prog prog =
	let stack = Array.make 8192 0
	and globals = Array.make prog.size_globals 0 in
	
	(*exec runs op at stack position
	  fp is frame pointer
	  sp is stack pointer
	  pc is program counter *)
	  
	let rec exec fp sp pc = match prog.text.(pc) with
	
		(*lits will push values on stack*)
		(*int: type 1 and value*)
		Litin i -> stack.(sp) <- i; stack.(sp+1) <- 1;  exec fp (sp+2) (pc+1)
		
		(* string: type 2, x, y, # of char, chars -- total size is automatically 30*)
	|	Litst str ->
		let trimmed = trim str in
		 let split_trim = Str.split(Str.regexp "\"") trimmed  in 
		  let ascii_list = List.rev (List.map Char.code (explode (List.nth(split_trim)(1)))) in
		   let length = List.length ascii_list in
		    let diff = 26 - length in
		     let coord_list = Str.split(Str.regexp "[ \t]+") (List.nth(split_trim)(0)) in
		      let rec fill_string remaining = if (remaining > 0) then (stack.(sp+diff-remaining) <- 0; 
		      			 fill_string (remaining-1)) else exec fp (sp+30) (pc+1) in 
		       let rec push_elements list index = if List.length list > 0 
					then (stack.(sp+diff+index) <- (List.hd list);
						  push_elements (List.tl list) (index+1)) 
		   			else (stack.(sp+26) <- length;
		   				  stack.(sp+27) <- int_of_string (List.nth(coord_list)(1)); 
		   			  	  stack.(sp+28) <- int_of_string (List.nth(coord_list)(0)); 
		   			  	  stack.(sp+29) <- 2;
		   			  	  fill_string diff)
		   				in
		    			push_elements ascii_list 0
	
		(* shape: type , push x1, push y1, push x2, push y2*)
	| 	Litsh shp -> 
		 let s_value = Str.split(Str.regexp("[ \t]+"))(shp) in
		 	stack.(sp+4) <- int_of_string (List.nth(s_value)(0));
		 	stack.(sp+3) <- int_of_string (List.nth(s_value)(1));
		 	stack.(sp+2) <- int_of_string (List.nth(s_value)(2));
		 	stack.(sp+1) <- int_of_string (List.nth(s_value)(3));
		 	stack.(sp) <- int_of_string (List.nth(s_value)(4));
		 	exec fp (sp+5) (pc+1)
		 	
		(*whatever is stored on top of stack*)
	| Drp -> 
		let obj_id = stack.(sp-1) in 
		(
			match obj_id with
				1 -> exec fp (sp-2) (pc+1)
			|	2 -> exec fp (sp-30) (pc+1)
			|	3 -> exec fp (sp-5) (pc+1)
			|	4 -> exec fp (sp-5) (pc+1)
			|	5 -> exec fp (sp-5) (pc+1)
			|	6 -> exec fp (sp-5) (pc+1)
			| _ -> raise(Failure("Unmatched type!!")))
	
	(*binary operation*)
	| Bin op -> let op1 = stack.(sp-4) and op2 = stack.(sp-2) in     
      	stack.(sp-4) <- (let boolean i = if i then 1 else 0 in
      	match op with
			Add     -> op1 + op2
      	| 	Sub     -> op1 - op2
      	| 	Mult    -> op1 * op2
      	| 	Div     -> op1 / op2
      	| 	Equal   -> boolean (op1 =  op2)
      	| 	Neq     -> boolean (op1 != op2)
      	| 	Less    -> boolean (op1 <  op2)
      	| 	Leq     -> boolean (op1 <= op2)
      	| 	Greater -> boolean (op1 >  op2)
      	| 	Geq     -> boolean (op1 >= op2)) ;
      	exec fp (sp-2) (pc+1)
			
	(*copy global variable onto stack
	  this is passed the first index on the array of globals that will hold the identifier*)
	| Lod index -> (* Fetch global variable *)
		let obj_id = globals.(index) in
		(
			match obj_id with
				1 -> 
					stack.(sp) <- globals.(index-1);
					stack.(sp+1) <- globals.(index);
					exec fp (sp+2) (pc+1)
					
			|	2 ->
					for i=0 to 29 do
						stack.(sp+i) <- globals.(index-29+i)
					done;
					exec fp (sp+30) (pc+1)
			
			|	3 -> 
					stack.(sp) <- globals.(index-4);
					stack.(sp+1) <- globals.(index-3);
					stack.(sp+2) <- globals.(index-2);
					stack.(sp+3) <- globals.(index-1);
					stack.(sp+4) <- globals.(index);
					exec fp (sp+5) (pc+1)
			|	4 -> 
					stack.(sp) <- globals.(index-4);
					stack.(sp+1) <- globals.(index-3);
					stack.(sp+2) <- globals.(index-2);
					stack.(sp+3) <- globals.(index-1);
					stack.(sp+4) <- globals.(index);
					exec fp (sp+5) (pc+1)
			|	5 -> 
					stack.(sp) <- globals.(index-4);
					stack.(sp+1) <- globals.(index-3);
					stack.(sp+2) <- globals.(index-2);
					stack.(sp+3) <- globals.(index-1);
					stack.(sp+4) <- globals.(index);
					exec fp (sp+5) (pc+1)
			|	6 -> 
					stack.(sp) <- globals.(index-4);
					stack.(sp+1) <- globals.(index-3);
					stack.(sp+2) <- globals.(index-2);
					stack.(sp+3) <- globals.(index-1);
					stack.(sp+4) <- globals.(index);
					exec fp (sp+5) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!"))
		) 
	| Loda index -> (* Fetch global array variable *)
		if (stack.(sp-1) <> 1) then raise(Failure("Array type check failure!")) else
		let loffset = stack.(sp-2) in
		let obj_id = globals.(index) in
		let lsize = (match obj_id with
					1 -> 2
				|	2 -> raise(Failure("No support of string array!"))
				|   3 -> 5
				|   4 -> 5
				|   5 -> 5
				|   6 -> 5 
				|   _ -> (ignore(print_endline(string_of_int(globals.(index)))); raise(Failure("TTType check error!")))) 
		in
		(
			match obj_id with
				1 -> 
					stack.(sp) <- globals.(index-1-lsize*loffset);
					stack.(sp+1) <- globals.(index-lsize*loffset);
					exec fp (sp+2) (pc+1)
					
			|	2 ->
					for i=0 to 29 do
						stack.(sp+i) <- globals.(index-29+i)
					done;
					exec fp (sp+30) (pc+1)
			
			|	3 -> 
					stack.(sp) <- globals.(index-4-lsize*loffset);
					stack.(sp+1) <- globals.(index-3-lsize*loffset);
					stack.(sp+2) <- globals.(index-2-lsize*loffset);
					stack.(sp+3) <- globals.(index-1-lsize*loffset);
					stack.(sp+4) <- globals.(index-lsize*loffset);
					exec fp (sp+5) (pc+1)
			|	4 -> 
					stack.(sp) <- globals.(index-4-lsize*loffset);
					stack.(sp+1) <- globals.(index-3-lsize*loffset);
					stack.(sp+2) <- globals.(index-2-lsize*loffset);
					stack.(sp+3) <- globals.(index-1-lsize*loffset);
					stack.(sp+4) <- globals.(index-lsize*loffset);
					exec fp (sp+5) (pc+1)
			|	5 -> 
					stack.(sp) <- globals.(index-4-lsize*loffset);
					stack.(sp+1) <- globals.(index-3-lsize*loffset);
					stack.(sp+2) <- globals.(index-2-lsize*loffset);
					stack.(sp+3) <- globals.(index-1-lsize*loffset);
					stack.(sp+4) <- globals.(index-lsize*loffset);
					exec fp (sp+5) (pc+1)
			|	6 -> 
					stack.(sp) <- globals.(index-4-lsize*loffset);
					stack.(sp+1) <- globals.(index-3-lsize*loffset);
					stack.(sp+2) <- globals.(index-2-lsize*loffset);
					stack.(sp+3) <- globals.(index-1-lsize*loffset);
					stack.(sp+4) <- globals.(index-lsize*loffset);
					exec fp (sp+5) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!"))
		) 
	
	(*store stack object in global variables given id*)
	| Str index ->
		let obj_id = stack.(sp-1) in
		( 
			match obj_id with
				1 -> 
					globals.(index-1) <- stack.(sp-2);
					globals.(index) <- stack.(sp-1);
					exec fp (sp) (pc+1)
			|	2 -> 
			
					for i=0 to 29 do
						globals.(index-29+i) <- stack.(sp-30+i)
					done;
					exec fp (sp) (pc+1)
					
			|	3 -> 
					globals.(index-4) <- stack.(sp-5);
					globals.(index-3) <- stack.(sp-4);
					globals.(index-2) <- stack.(sp-3);
					globals.(index-1) <- stack.(sp-2);
					globals.(index) <- stack.(sp-1);
					exec fp (sp) (pc+1)
					
			|	4 -> 
					globals.(index-4) <- stack.(sp-5);
					globals.(index-3) <- stack.(sp-4);
					globals.(index-2) <- stack.(sp-3);
					globals.(index-1) <- stack.(sp-2);
					globals.(index) <- stack.(sp-1);
					exec fp (sp) (pc+1)
			|	5 -> 
					globals.(index-4) <- stack.(sp-5);
					globals.(index-3) <- stack.(sp-4);
					globals.(index-2) <- stack.(sp-3);
					globals.(index-1) <- stack.(sp-2);
					globals.(index) <- stack.(sp-1);
					exec fp (sp) (pc+1)
			|	6 -> 
					globals.(index-4) <- stack.(sp-5);
					globals.(index-3) <- stack.(sp-4);
					globals.(index-2) <- stack.(sp-3);
					globals.(index-1) <- stack.(sp-2);
					globals.(index) <- stack.(sp-1);
					exec fp (sp) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!")))
	
	(*store stack object in global variables given id*)
	| Stra index ->
		if (stack.(sp-1) <> 1) then raise(Failure("Array type check failure!")) else
		let obj_id = stack.(sp-3) 
		and loffset = stack.(sp-2)
		in
		( 
			match obj_id with
				1 -> 
					globals.(index-1-2*loffset) <- stack.(sp-2-2);
					globals.(index-2*loffset) <- stack.(sp-1-2);
					exec fp (sp) (pc+1)
			|	2 -> 
			
					for i=0 to 29 do
						globals.(index-29+i) <- stack.(sp-30+i)
					done;
					exec fp (sp) (pc+1)
					
			|	3 -> 
					globals.(index-4-5*loffset) <- stack.(sp-5-2);
					globals.(index-3-5*loffset) <- stack.(sp-4-2);
					globals.(index-2-5*loffset) <- stack.(sp-3-2);
					globals.(index-1-5*loffset) <- stack.(sp-2-2);
					globals.(index-5*loffset) <- stack.(sp-1-2);
					exec fp (sp) (pc+1)
					
			|	4 -> 
					globals.(index-4-5*loffset) <- stack.(sp-5-2);
					globals.(index-3-5*loffset) <- stack.(sp-4-2);
					globals.(index-2-5*loffset) <- stack.(sp-3-2);
					globals.(index-1-5*loffset) <- stack.(sp-2-2);
					globals.(index-5*loffset) <- stack.(sp-1-2);
					exec fp (sp) (pc+1)
			|	5 -> 
					globals.(index-4-5*loffset) <- stack.(sp-5-2);
					globals.(index-3-5*loffset) <- stack.(sp-4-2);
					globals.(index-2-5*loffset) <- stack.(sp-3-2);
					globals.(index-1-5*loffset) <- stack.(sp-2-2);
					globals.(index-5*loffset) <- stack.(sp-1-2);
					exec fp (sp) (pc+1)
			|	6 -> 
					globals.(index-4-5*loffset) <- stack.(sp-5-2);
					globals.(index-3-5*loffset) <- stack.(sp-4-2);
					globals.(index-2-5*loffset) <- stack.(sp-3-2);
					globals.(index-1-5*loffset) <- stack.(sp-2-2);
					globals.(index-5*loffset) <- stack.(sp-1-2);
					exec fp (sp) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!")))
				
	(* same operations as in microc *)
	| Lfp i -> 
		let obj_id = stack.(fp+i) in
		( 
			match obj_id with
				1 -> 
					stack.(sp) <- stack.(fp+i-1);
					stack.(sp+1) <- stack.(fp+i);
					exec fp (sp+2) (pc+1)
			|	2 -> 
					for j=0 to 29 do
						stack.(sp+j) <- stack.(fp+i-29+j)
					done;
					exec fp (sp+30) (pc+1)
			|	3 ->
					stack.(sp) <- stack.(fp+i-4);
					stack.(sp+1) <- stack.(fp+i-3);
					stack.(sp+2) <- stack.(fp+i-2);
					stack.(sp+3) <- stack.(fp+i-1);
					stack.(sp+4) <- stack.(fp+i);
					exec fp (sp+5) (pc+1)
			|	4 -> 
					stack.(sp) <- stack.(fp+i-4);
					stack.(sp+1) <- stack.(fp+i-3);
					stack.(sp+2) <- stack.(fp+i-2);
					stack.(sp+3) <- stack.(fp+i-1);
					stack.(sp+4) <- stack.(fp+i);
					exec fp (sp+5) (pc+1)
			|	5 -> 
					stack.(sp) <- stack.(fp+i-4);
					stack.(sp+1) <- stack.(fp+i-3);
					stack.(sp+2) <- stack.(fp+i-2);
					stack.(sp+3) <- stack.(fp+i-1);
					stack.(sp+4) <- stack.(fp+i);
					exec fp (sp+5) (pc+1)
			|	6 -> 
					stack.(sp) <- stack.(fp+i-4);
					stack.(sp+1) <- stack.(fp+i-3);
					stack.(sp+2) <- stack.(fp+i-2);
					stack.(sp+3) <- stack.(fp+i-1);
					stack.(sp+4) <- stack.(fp+i);
					exec fp (sp+5) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!")))

	| Lfpa i -> (* This is the base address of array. Now, on top of stack, it's the element offset*)
		if (stack.(sp-1) <> 1 ) then raise(Failure("Array index type check failure!!")) else
		let obj_id = stack.(fp+i)
		and loffset = stack.(sp-2) in
		( 
			match obj_id with
				1 -> 
					stack.(sp) <- stack.(fp+i-1-loffset*2);
					stack.(sp+1) <- stack.(fp+i-loffset*2);
					exec fp (sp+2) (pc+1)
			|	2 -> 
					for j=0 to 29 do
						stack.(sp+j) <- stack.(fp+i-29+j)
					done;
					exec fp (sp+30) (pc+1)
			|	3 ->
					stack.(sp) <- stack.(fp+i-4-loffset*5);
					stack.(sp+1) <- stack.(fp+i-3-loffset*5);
					stack.(sp+2) <- stack.(fp+i-2-loffset*5);
					stack.(sp+3) <- stack.(fp+i-1-loffset*5);
					stack.(sp+4) <- stack.(fp+i-loffset*5);
					exec fp (sp+5) (pc+1)
			|	4 -> 
					stack.(sp) <- stack.(fp+i-4-loffset*5);
					stack.(sp+1) <- stack.(fp+i-3-loffset*5);
					stack.(sp+2) <- stack.(fp+i-2-loffset*5);
					stack.(sp+3) <- stack.(fp+i-1-loffset*5);
					stack.(sp+4) <- stack.(fp+i-loffset*5);
					exec fp (sp+5) (pc+1)
			|	5 -> 
					stack.(sp) <- stack.(fp+i-4-loffset*5);
					stack.(sp+1) <- stack.(fp+i-3-loffset*5);
					stack.(sp+2) <- stack.(fp+i-2-loffset*5);
					stack.(sp+3) <- stack.(fp+i-1-loffset*5);
					stack.(sp+4) <- stack.(fp+i-loffset*5);
					exec fp (sp+5) (pc+1)
			|	6 -> 
					stack.(sp) <- stack.(fp+i-4-loffset*5);
					stack.(sp+1) <- stack.(fp+i-3-loffset*5);
					stack.(sp+2) <- stack.(fp+i-2-loffset*5);
					stack.(sp+3) <- stack.(fp+i-1-loffset*5);
					stack.(sp+4) <- stack.(fp+i-loffset*5);
					exec fp (sp+5) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!")))
		
	| Sfp i -> 
		let obj_id = stack.(sp-1) in
		( 
			match obj_id with
				1 -> stack.(fp+i) <- stack.(sp-1); stack.(fp+i-1) <- stack.(sp-2); exec fp (sp) (pc+1)

			|	2 -> 
					for j=0 to 29 do
						stack.(fp+i-j) <- stack.(sp-j-1)
					done;
					exec fp (sp) (pc+1)

			|	3 ->
					stack.(fp+i) <- stack.(sp-1);
					stack.(fp+i-1) <- stack.(sp-2);
					stack.(fp+i-2) <- stack.(sp-3);
					stack.(fp+i-3) <- stack.(sp-4);
					stack.(fp+i-4) <- stack.(sp-5);
					exec fp (sp) (pc+1)
			|	4 -> 
					stack.(fp+i) <- stack.(sp-1);
					stack.(fp+i-1) <- stack.(sp-2);
					stack.(fp+i-2) <- stack.(sp-3);
					stack.(fp+i-3) <- stack.(sp-4);
					stack.(fp+i-4) <- stack.(sp-5);
					exec fp (sp) (pc+1)
			|	5 -> 
					stack.(fp+i) <- stack.(sp-1);
					stack.(fp+i-1) <- stack.(sp-2);
					stack.(fp+i-2) <- stack.(sp-3);
					stack.(fp+i-3) <- stack.(sp-4);
					stack.(fp+i-4) <- stack.(sp-5);
					exec fp (sp) (pc+1)
			|	6 -> 
					stack.(fp+i) <- stack.(sp-1);
					stack.(fp+i-1) <- stack.(sp-2);
					stack.(fp+i-2) <- stack.(sp-3);
					stack.(fp+i-3) <- stack.(sp-4);
					stack.(fp+i-4) <- stack.(sp-5);
					exec fp (sp) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!")))

	| Sfpa i -> 
		if (stack.(sp-1) <> 1) then raise(Failure("Array index type error in Sfpa!!")) else 
		let obj_id = stack.(sp-3) 
		and loffset = stack.(sp-2) in
		( 
			match obj_id with
				1 -> stack.(fp+i-2*loffset) <- stack.(sp-1-2); 
					 stack.(fp+i-1-2*loffset) <- stack.(sp-2-2); 
					 exec fp (sp) (pc+1)
			|	2 -> 
					for j=0 to 29 do
						stack.(fp+i-j) <- stack.(sp-j-1)
					done;
					exec fp (sp) (pc+1)
			|	3 ->
					stack.(fp+i-5*loffset) <- stack.(sp-1-2);
					stack.(fp+i-1-5*loffset) <- stack.(sp-2-2);
					stack.(fp+i-2-5*loffset) <- stack.(sp-3-2);
					stack.(fp+i-3-5*loffset) <- stack.(sp-4-2);
					stack.(fp+i-4-5*loffset) <- stack.(sp-5-2);
					exec fp (sp) (pc+1)
			|	4 -> 
					stack.(fp+i-5*loffset) <- stack.(sp-1-2);
					stack.(fp+i-1-5*loffset) <- stack.(sp-2-2);
					stack.(fp+i-2-5*loffset) <- stack.(sp-3-2);
					stack.(fp+i-3-5*loffset) <- stack.(sp-4-2);
					stack.(fp+i-4-5*loffset) <- stack.(sp-5-2);
					exec fp (sp) (pc+1)
			|	5 -> 
					stack.(fp+i-5*loffset) <- stack.(sp-1-2);
					stack.(fp+i-1-5*loffset) <- stack.(sp-2-2);
					stack.(fp+i-2-5*loffset) <- stack.(sp-3-2);
					stack.(fp+i-3-5*loffset) <- stack.(sp-4-2);
					stack.(fp+i-4-5*loffset) <- stack.(sp-5-2);
					exec fp (sp) (pc+1)
			|	6 -> 
					stack.(fp+i-5*loffset) <- stack.(sp-1-2);
					stack.(fp+i-1-5*loffset) <- stack.(sp-2-2);
					stack.(fp+i-2-5*loffset) <- stack.(sp-3-2);
					stack.(fp+i-3-5*loffset) <- stack.(sp-4-2);
					stack.(fp+i-4-5*loffset) <- stack.(sp-5-2);
					exec fp (sp) (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!")))
	
	(*draw shape currently on top of stack*)
	| Jsr(-1) ->
		let obj_id = stack.(sp-1) in 
		(
			match obj_id with
				1 -> raise (IllegalPrint); 
			|	2 ->
					let size = stack.(sp-4) in
						let rec make_string current_string counter = if counter < size 
							then  (make_string (current_string ^ Char.escaped(Char.chr stack.(sp-5-counter)))(counter+1))
							else (current_string) in 
								let this_will_work = (make_string("")(0)) in 
								Graphics.moveto(stack.(sp-2))(stack.(sp-3));
								Graphics.draw_string (this_will_work);
								exec fp sp (pc+1)
								
			|	3 -> 
					Graphics.draw_rect(stack.(sp-2)) (stack.(sp-3)) (stack.(sp-4)) (stack.(sp-5));
					exec fp sp (pc+1)
			|	4 ->
					Graphics.draw_ellipse(stack.(sp-2)) (stack.(sp-3)) (stack.(sp-4)) (stack.(sp-5));
					exec fp sp (pc+1)
			|	5 ->
					Graphics.moveto(stack.(sp-2)) (stack.(sp-3));
	  				Graphics.lineto(stack.(sp-4)) (stack.(sp-5));
	  				exec fp sp (pc+1)
			|	6 -> raise (IllegalPrint)
			|   _ -> raise (IllegalPrint))
			
	(*suspend program*)
	| Jsr(-2) -> 
				let duration = stack.(sp-2) in
					Thread.join(Thread.create(Thread.delay)(float_of_int duration /. 1000.0)); 
					Graphics.clear_graph (); 
					exec fp (sp) (pc+1)
					
	(*print int to command line for debug purposes*)
	| Jsr(-4) -> print_endline(string_of_int stack.(sp-2)); exec fp sp (pc+1)
	
	(*dump complete stack to command line*)
	| Jsr(-5) -> Array.iter print_endline (Array.map string_of_int stack); 
			
	| Jsr i -> stack.(sp) <- pc+1; exec fp (sp+1) i (* stores current pc and execute on i. *)
	| Ent i -> stack.(sp) <- fp; exec sp (sp+i+1) (pc+1)
	| Rts i ->
		let new_fp = stack.(fp) and new_pc = stack.(fp-1) and base = fp-i-1 in 
			(
			let obj_id = stack.(sp-1) in
			match obj_id with
				1 -> (stack.(base+1) <- stack.(sp-1);  (* Construct an int on top of stack*)
					 stack.(base) <- stack.(sp-2);
					 exec new_fp (base+2) new_pc
					 )
			|	2 ->
					let sp_temp = Array.make 30 0 in
					for j=0 to 29 do
						sp_temp.(j) <- stack.(sp+j-30)
					done;
					for j=0 to 29 do
						stack.(base+j) <- sp_temp.(j)
					done;
					exec new_fp (base+30) new_pc
			
			|	3 -> let sp1 = stack.(sp-1) 
					 and sp2 = stack.(sp-2) 
					 and sp3 = stack.(sp-3) 
					 and sp4 = stack.(sp-4) 
					 and sp5 = stack.(sp-5) in
					 (stack.(base+4) <- sp1;  (* Construct an int on top of stack*)
					 stack.(base+3) <- sp2;
					 stack.(base+2) <- sp3;
					 stack.(base+1) <- sp4;
					 stack.(base) <- sp5;
					 exec new_fp (base+5) new_pc
					 )
			|	4 -> let sp1 = stack.(sp-1) 
					 and sp2 = stack.(sp-2) 
					 and sp3 = stack.(sp-3) 
					 and sp4 = stack.(sp-4) 
					 and sp5 = stack.(sp-5) in
					 (stack.(base+4) <- sp1;  (* Construct an int on top of stack*)
					 stack.(base+3) <- sp2;
					 stack.(base+2) <- sp3;
					 stack.(base+1) <- sp4;
					 stack.(base) <- sp5;
					 exec new_fp (base+5) new_pc
					 )
			|	5 -> let sp1 = stack.(sp-1) 
					 and sp2 = stack.(sp-2) 
					 and sp3 = stack.(sp-3) 
					 and sp4 = stack.(sp-4) 
					 and sp5 = stack.(sp-5) in
					 (stack.(base+4) <- sp1;  (* Construct an int on top of stack*)
					 stack.(base+3) <- sp2;
					 stack.(base+2) <- sp3;
					 stack.(base+1) <- sp4;
					 stack.(base) <- sp5;
					 exec new_fp (base+5) new_pc
					 )
			| _ -> raise(Failure("Unmatched type!!"));
			);
	| Beq i -> exec fp (sp-1) (pc + if stack.(sp-2) = 0 then i else 1)
	| Bne i -> exec fp (sp-1)(pc + if stack.(sp-2)!= 0 then i else 1)
	| Bra i -> exec fp sp (pc+i)
	| Hlt -> ()
	
	(*funcitonality that differs from micro c*)
	(*create empty graph*)
	| Sgraph -> Graphics.open_graph ""; exec fp (sp) (pc+1)
	(*clear graph*)
	| Egraph -> Graphics.clear_graph (); exec fp (sp) (pc+1)
	
	(*move object on top of stack by ints in stack above*)
	| Movby -> 
		let deltax = stack.(sp-2) in 
		 let deltay = stack.(sp-4) in
		  let obj_id = stack.(sp-5) in
		  (
			match obj_id with
				1 -> raise (IllegalMove)
			|	2 -> 
					stack.(sp-6) <- (stack.(sp-6) + deltax);
					stack.(sp-7) <- (stack.(sp-7) + deltay);
					exec fp sp (pc+1)
			|	3 ->
					stack.(sp-6) <- (stack.(sp-6) + deltax);
					stack.(sp-7) <- (stack.(sp-7) + deltay);
					exec fp sp (pc+1)
			|	4 ->
					stack.(sp-6) <- (stack.(sp-6) + deltax);
					stack.(sp-7) <- (stack.(sp-7) + deltay);
					exec fp sp (pc+1)
			|	5 ->
					stack.(sp-6) <- (stack.(sp-6) + deltax);
					stack.(sp-7) <- (stack.(sp-7) + deltay);
					stack.(sp-8) <- (stack.(sp-8) + deltax);
					stack.(sp-9) <- (stack.(sp-9) + deltay);
					exec fp sp (pc+1)
			|	6 ->
					stack.(sp-6) <- (stack.(sp-6) + deltax);
					stack.(sp-7) <- (stack.(sp-7) + deltay);
					exec fp sp (pc+1)
					
			| _ -> raise(Failure("Unmatched type!!"))) 
					
	(*move object on top of stack by ints in stack above*)
	| Movto -> 
		let newx = stack.(sp-2) in 
		 let newy = stack.(sp-4) in
		  let obj_id = stack.(sp-5) in
		  (
			match obj_id with
				1 -> raise (IllegalMove)
			|	2 -> 
					stack.(sp-6) <- newx;
					stack.(sp-7) <- newy;
					exec fp sp (pc+1)
			|	3 ->
					stack.(sp-6) <- newx;
					stack.(sp-7) <- newy;
					exec fp sp (pc+1)
			|	4 ->
					stack.(sp-6) <- newx;
					stack.(sp-7) <- newy;
					exec fp sp (pc+1)
			|	5 ->
					let deltax = ( newx - stack.(sp-6)) in
					 let deltay = ( newy - stack.(sp-7)) in
						stack.(sp-6) <- newx;
						stack.(sp-7) <- newy;
						stack.(sp-8) <- (stack.(sp-8) + deltax);
						stack.(sp-9) <- (stack.(sp-9) + deltay);
						exec fp sp (pc+1)
			|	6 ->
					stack.(sp-6) <- newx;
					stack.(sp-7) <- newy;
					exec fp sp (pc+1)
			| _ -> raise(Failure("Unmatched type!!"))) 
	
	(*get coordinate of object on stack -- the type of coordinate is specified by the int on top of the object on teh stack*)		
	| GetC ->
		let coord_type = stack.(sp-2) in
			let coord = stack.(sp-3-coord_type) in
				stack.(sp) <- coord;
				stack.(sp+1) <- 1;
				exec fp (sp+2) (pc+1)

    | MakeS -> (* Takes the top five integers of stack and put back a shape. *)
		let v1 = stack.(sp-1) 
		and v2 = stack.(sp-3) 
		and v3 = stack.(sp-5) 
		and v4 = stack.(sp-7) 
		and v5 = stack.(sp-9)
		in
		if ((v1 <> 1) || (v2 <> 1) || (v3 <> 1) || (v4 <> 1) || (v5 <> 1)) then 
			raise(Failure("MakeS type check error!")) else
		( 
			stack.(sp-1) <- stack.(sp-2);
			stack.(sp-2) <- stack.(sp-4);
			stack.(sp-3) <- stack.(sp-6);
			stack.(sp-4) <- stack.(sp-8);
			stack.(sp-5) <- stack.(sp-10);
			exec fp sp (pc+1)
		)
	| _ -> raise(Failure("Illegal Bytecode Operation!!"))
			
	
(*execute first line*)	
in exec 0 0 0



	
